<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <button id="btn">点击发送ajax请求</button>
    <script>
      // 发送ajax请求的函数
      function myAjax(options) {
        // 1.判断使用者使用时,是否传递配置对象,如果没有传递,则直接return
        if (!options) return
        // 2. 解构options中的配置属性
        let {
          url,
          method = 'get', // 4. 如果没有传入method,则使用默认值'get'
          data,
          timeout = 2000,
          dataType,
          success,
          error,
          complete,
          beforeSend,
        } = options
        // 3. 判断是否传入了url.如果传入了url则继续执行,否则,return
        if (!url) return

        // 5. 创建xhr对象
        const xhr = new XMLHttpRequest()

        // 设置超时时间
        xhr.timeout = timeout
        // 6. 设置请求方式和url地址
        // 6.1 先将用户传入的data(对象)的数据,拼接成一个键=值&键=值的字符串
        // obj2str的返回值有两种可能: 1. 拼接好的字符串 2. undefined
        let params = obj2str(data)
        //如果是get请求并且拼接完之后有参数,则拼接,否则不拼接
        if (method === 'get' && params) {
          url += `?${params}`
          params = null
        }
        xhr.open(method, url)

        // 7. 设置请求头
        if (method === 'post') {
          xhr.setRequestHeader(
            'content-type',
            'application/x-www-form-urlencoded'
          )
        }

        // beforeSend应该在send之前调用
        const result = beforeSend && beforeSend()
        if (result === false) return
        // 8. 设置请求主体,并发送请求
        xhr.send(params)

        // 9. 接收响应
        xhr.onreadystatechange = function () {
          if (xhr.readyState === 4) {
            complete && complete()
            if (xhr.status === 200) {
              // 获取到响应主体的数据,此时data一定是一个字符串
              let data = xhr.responseText
              if (dataType === 'json') {
                // 如果dataType的值是json,就要去解析json字符串,但是有可能响应的数据不是json字符串,此时解析错误,则调用error
                try {
                  data = JSON.parse(data)
                } catch (err) {
                  error && error()
                  return
                }
                success && success(data)
              } else if (dataType === 'text') {
                // 如果dataType是text,则直接响应响应主体内容即可
                success && success(data)
              } else {
                // 如果没写dataType.则自动判断
                // 直接传入JSON.parse进行转换,.如果是json格式的字符串,则会转成成功,如果不是json字符串,会报错
                try {
                  data = JSON.parse(data)
                } catch (error) {
                  console.log(error)
                }
                success && success(data)
              }
            } else {
              error && error()
            }
          }
        }
      }

      // 将对象转成键值对的字符串的函数
      function obj2str(data) {
        // 如果没有data,就直接return
        // {name: 'zs', age: 18} ==> name=zs&age=18
        if (!data) return
        // 声明一个变量,用来存储拼接的字符串
        // 由于字符串不可变,所以直接拼接字符串,有产生大量无用的字符串
        // let str = ''
        // for (let key in data) {
        //   str += `${key}=${data[key]}&`
        // }

        // 推荐的拼接字符串的方式
        let arr = []
        for (let key in data) {
          arr.push(`${key}=${data[key]}`)
        }
        return arr.join('&')
      }

      btn.onclick = function () {
        myAjax({
          url: 'http://localhost:5000/test',
          method: 'post',
          data: {
            name: 'xx',
            age: 20,
          },
          dataType: 'json',
          // timeout: 1000,
          // beforeSend() {
          //   console.log('请求之前调用')
          //   return 0
          // },
          // complete() {
          //   console.log('响应完成调用')
          // },
          success(data) {
            console.log('响应成功', data)
          },
          error() {
            console.log('响应失败')
          },
        })
      }
    </script>
  </body>
</html>
